#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"
#include <future>
#include <functional>
#include <optional>

/*
所以requestor这个模块就是提供dispatcher模块onresponse接口，管理连接的描述
以及提供两个send方式给rpc_caller和别的模块
rpc_caller模块利用send方式提供具体发送接收方法

send方式可以决定你这个调用方法是同步方式(send同步+send异步)还是异步方式(send回调)
*/

namespace bitrpc
{
    namespace client
    {
        class Requestor
        {
        public:
            using ptr = std::shared_ptr<Requestor>;
            using RequestCallback = std::function<void(const BaseMessage::ptr &)>;
            using AsyncResponse = std::future<BaseMessage::ptr>; // 用来获取异步结果
            struct RequestDescribe
            {
                using ptr = std::shared_ptr<RequestDescribe>;
                BaseMessage::ptr request;
                RType rtype;
                std::promise<BaseMessage::ptr> response;
                RequestCallback callback;
            };
            void onResponse(const BaseConnection::ptr &conn, BaseMessage::ptr &msg) /* 用于接收的模块，注册给了dispatcher */
            {
                std::string rid = msg->rid();
                RequestDescribe::ptr rdp = getDescribe(rid);
                if (rdp.get() == nullptr)
                {
                    ELOG("收到响应 - %s，但是未找到对应的请求描述！", rid.c_str());
                    return;
                }
                if (rdp->rtype == RType::REQ_ASYNC)
                {
                    rdp->response.set_value(msg); //  std::promise<BaseMessage::ptr> response;将结果设置进promise中
                }
                else if (rdp->rtype == RType::REQ_CALLBACK)
                {
                    if (rdp->callback)
                        rdp->callback(msg);
                }
                else
                {
                    ELOG("请求类型未知！！");
                }
                delDescribe(rid);
            }
            /* 选择异步future的目的就是让promise在任何地方都可以设置进数据，利用异步future需要让future.get()和异步的任务在一个执行流或者两个执行流  */
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, AsyncResponse &async_rsp)
            {
                /* 异步send是new一个有promise */
                DLOG("进入 send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, AsyncResponse &async_rsp)");
                RequestDescribe::ptr rdp = newDescribe(req, RType::REQ_ASYNC);
                if (rdp.get() == nullptr)
                {
                    ELOG("构造请求描述对象失败！");
                    return false;
                }
                DLOG("构造请求描述对象成功！");
                // req->debugprint();
                conn->send(req);
                async_rsp = rdp->response.get_future(); /* rdp的future获得promise对应的future */
                return true;
            }
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, BaseMessage::ptr &rsp) /* 调用send */
            {
                DLOG("调用send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, BaseMessage::ptr &rsp)！");
                AsyncResponse rsp_future;               // using AsyncResponse = std::future<BaseMessage::ptr>;
                bool ret = send(conn, req, rsp_future); /* 去调用上方send */
                if (ret == false)
                {
                    return false;
                }
                rsp = rsp_future.get(); // set_value的接口(在提供给dispatcher的接口onresponse中)
                return true;
            }
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, const RequestCallback &cb)
            {
                RequestDescribe::ptr rdp = newDescribe(req, RType::REQ_CALLBACK, cb);
                if (rdp.get() == nullptr)
                {
                    ELOG("构造请求描述对象失败！");
                    return false;
                }
                conn->send(req);
                return true;
            }

        private:
            RequestDescribe::ptr newDescribe(const BaseMessage::ptr &req, RType rtype,
                                             const RequestCallback &cb = RequestCallback())
            {
                /* std::promise会调用默认构造初始化 */
                std::unique_lock<std::mutex> lock(_mutex);
                RequestDescribe::ptr rd = std::make_shared<RequestDescribe>();
                rd->request = req;
                rd->rtype = rtype;
                if (rtype == RType::REQ_CALLBACK && cb)
                {
                    rd->callback = cb;
                }
                _request_desc.insert(std::make_pair(req->rid(), rd));
                DLOG("newDescribe成功！");
                return rd;
            }
            RequestDescribe::ptr getDescribe(const std::string &rid)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _request_desc.find(rid);
                if (it == _request_desc.end())
                {
                    return RequestDescribe::ptr();
                }
                return it->second;
            }
            void delDescribe(const std::string &rid)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _request_desc.erase(rid);
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, RequestDescribe::ptr> _request_desc;
        };
    }
}

/*
    用来转发业务的请求以及等待response的模块
    std::string rid ,RequestDescribe (一个请求对应一个rid，对应一个请求描述)   这个请求描述是在业务层调用call(send()的时候创建的)
    struct RequestDescribe {
                    using ptr = std::shared_ptr<RequestDescribe>;
                    BaseMessage::ptr request;  // 对应的请求消息(Rpc调用，service注册)
                    RType rtype;   //send的类型(callback/async)
                    std::promise<BaseMessage::ptr> response; //用来等待异步结果的
                    RequestCallback callback;
                };

    这个模块就是转发请求，将请求描述保存在自己内部，收到response后通过请求描述做分析
     bool call(const BaseConnection::ptr &conn, const std::string &method,
                      const Json::Value &params, const JsonResponseCallback &cb)
            {
               ////

                Requestor::RequestCallback req_cb = std::bind(&RpcCaller::Callback1,
                                                              this, cb, std::placeholders::_1);
                bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), req_cb);
                if (ret == false)
                {
                    ELOG("回调Rpc请求失败！");
                    return false;
                }
                return true;
            }
*/